import _ from 'lodash';
import qs from '@src/util/querystring2';
import querystring from './querystring';
// https://github.com/axios/axios
import axios from 'axios';
import decode from 'entity-decode';
import { userCenterGetTokenInfo, userCenterErrorHandler } from './userCenter';
import { localStorageKey, defaultLanguage, httpHeaderKey } from 'pub-bbx-global/lang/dist';
import { useTimezone } from 'pub-bbx-utils';

let alertLoginAgain = false;
/**
 *  是否为blob
 */
function isBlob(blobObject) {
  return blobObject instanceof Blob;
}
/**
 * 对params进行编码格式如下：
 * key=value&key1=value1
 */
function encodeParams(params) {
  let str = '';
  if (Object.keys(params).length > 0) {
    for (let name in params) {
      if (params[name] == null) {
        str += `&${name}=`;
      } else {
        str += `&${name}=${encodeURIComponent(params[name])}`;
      }
    }
    str = str.substring(1);
  }
  return str;
}

/**
 * @des a链接文件下载需要添加鉴权请求头
 */
export function downloadByhref({href, name}) {
  const tokenInfo = userCenterGetTokenInfo();
  fetch(href, {
    method: 'GET',
    headers: new Headers({
      token: tokenInfo?.token || '',
      shbVersion: tokenInfo?.shbVersion || '',
    }),
  })
    .then(res => res.blob())
    .then(data => {
      const blobUrl = window.URL.createObjectURL(data);
      const a = document.createElement('a');
      a.download = name;
      a.href = blobUrl;
      a.click();
      URL.revokeObjectURL(a.href); // 释放内存
    });
}

const axiosIns = axios.create({
  // put, post, patch 请求参数转换
  transformRequest: [
    function (data, headers) {
      let copyData = data;
      if (headers['Content-Type'] == 'application/x-www-form-urlencoded' && _.isPlainObject(copyData)) {
        let isArrayIndices = headers.indices === true;
        const ArrayFormatMode = headers.arrayFormat;
        copyData = querystring.stringify(copyData, isArrayIndices, ArrayFormatMode);
      }

      if (headers['Content-Type'] == 'application/json') {
        copyData = JSON.stringify(copyData);
      }

      return copyData;
    },
  ],
  // get 请求参数序列化
  paramsSerializer(params) {
    return querystring.stringify(params);
  },
});

let CancelToken = axios.CancelToken; // 取消令牌
let requestPool = {}; // 请求池

function removeFromPool(key) {
  let cancelFn = requestPool[key];
  if (typeof cancelFn == 'function') {
    cancelFn(`Request cancelled: ${key}`);
    delete requestPool[key];
  }
}

/** 请求拦截，取消对同一地址的重复请求，只保留最后一次请求 */
axiosIns.interceptors.request.use(
  config => {
    if (config.cancelable) {
      // 如果请求可取消
      let key = `${config.method}_${config.url}`;
      removeFromPool(key); // 取消重复请求

      // 生成取消token
      config.cancelToken = new CancelToken(function (cancelFunction) {
        requestPool[key] = cancelFunction;
      });
    }

    const tokenInfo = userCenterGetTokenInfo();

    if (tokenInfo.token && tokenInfo.shbVersion) {
      config.headers['token'] = tokenInfo.token;
      config.headers['shbVersion'] = tokenInfo.shbVersion;
    }

    config.headers[httpHeaderKey] = localStorage.getItem(localStorageKey) || defaultLanguage; // 传递语言环境
    config.headers['timeZone'] = useTimezone().timezone;

    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

// 添加响应拦截器
axiosIns.interceptors.response.use(
  response => {
    let config = response.config;
    let key = `${config.method}_${config.url}`;
    removeFromPool(key);

    if (alertLoginAgain) return;
    if (response.data.status == '2016') alertLoginAgain = true;
    // 用户中心错误处理
    userCenterErrorHandler(response);

    return response;
  },
  error => {
    return Promise.reject(error); // 返回一个空对象，主要是防止控制台报错
  }
);

function get(url = '', params = {}, emulateJSON = true, option = {}) {
  return axiosHttp('get', url, params, emulateJSON, option);
}

function post(url = '', params = {}, emulateJSON = true, option = {}) {
  return axiosHttp('post', url, params, emulateJSON, option);
}

function appPost(url = '', params = {}, emulateJSON = true, option = {}) {
  return axiosHttp('post', url, encodeParams(params), emulateJSON, option);
}

function axiosHttp(method = 'get', url = '', params = {}, emulateJSON = true, config = {}) {
  if (!config.headers) config.headers = {};

  if (method == 'get') {
    config.params = params;
    config.params._t = (Math.random() * 100000) >> 0;
  }

  if (method == 'post') {
    config.headers['Content-Type'] = emulateJSON ? 'application/json' : 'application/x-www-form-urlencoded';
    config.data = params;
  }

  config.url = url;
  if (location.port !== '') {
    // vite 启动 没有 process
    config.url = `/serve${url}`;
  }
  config.method = method;

  // 禁止在此处捕获异常
  // 如需统一处理，需要在处理后抛出异常，确保调用者可以处理异常
  return axiosIns.request(config).then(response => {
    let data = response && response.data;

    if (isBlob(data)) {
      return data;
    }

    let escapeData = null;

    try {
      // 处理后端返回值转义字符
      let decodeData = decode(JSON.stringify(data));
      escapeData = JSON.parse(decodeData);
    } catch (error) {
      escapeData = data;
    }

    return escapeData;
  });
}

/**
 * 文件下载
 * @param {*} url 地址
 * @param {*} params 参数
 * @param {*} config
 * @returns
 */
function downloadFile(url = '', data = {}, method = 'GET', config = {}) {
  if (!config.headers) config.headers = {};
  method = method.toUpperCase();
  data._t = (Math.random() * 100000) >> 0;

  const options = {
    url,
    headers: config.header || {},
    method,
    params: method === 'GET' ? data : { _t: data._t },
    data,
    responseType: 'blob',
  };

  options.headers['Content-Type'] = config.emulateJSON !== false ? 'application/json' : 'application/x-www-form-urlencoded';
  options.headers[httpHeaderKey] = localStorage.getItem(localStorageKey) || defaultLanguage; // 传递语言环境
  return axiosIns.request(options).then(res => {
    let blob = res && res.data;

    const { filename } = qs.parseParams(res.headers['content-disposition'], ';'); // 返回文件描述信息 filename

    if (navigator.msSaveOrOpenBlob) {
      navigator.msSaveBlob(blob, filename);
    } else {
      const link = document.createElement('a');
      link.href = URL.createObjectURL(blob); // 设置url
      link.download = filename; // 文件名
      link.click(); // 触发下载
      URL.revokeObjectURL(link.href); // 释放内存
    }
  });
}

const http = { get, post, axios: axiosHttp, appPost, downloadFile };

export default http;
